﻿#ifndef h_xmlH
#define h_xmlH

namespace h_xml
{

class HXmlTree
{
public :
   typedef pair<const HXmlTree*, const HString*> HPropertyKey;
   typedef map<HPropertyKey, HString> HPropertyMap;
// 根节点
   explicit HXmlTree();
// 子节点
   explicit HXmlTree(HXmlTree *Parent, const HString &Tag);
// 共享数据根节点
   explicit HXmlTree(HXmlTree *Env);
   ~HXmlTree(void);

   bool operator==(const HXmlTree &rhs);
   bool operator!=(const HXmlTree &rhs);

// 获得最后一次操作的错误信息
   const HString& GetErrorString(void);

// 设置/获得本结点的标签（即名称）
   void SetTag(const HString &Tag);
   const HString& GetTag(void);

// 设置/获得本结点的数据
   void SetData(const HString &Data);
   const HString& GetData(void);

// 设置删除标志
   void SetDeleteFlag();

// 设置/获得本结点的属性
   void SetProperty(const HString &PropertyName, const HString &PropertyValue, const HString &Default = "");
   void SetProperty(const char *Tag, int Num);
   const HString GetProperty(const HString &PropertyName, const HString &Default = "");
   HString GetPropertyUpper(const HString &PropertyName, const HString &Default = "");
   HString GetPropertyEnv(const HString &PropertyName, const HString &Default = "");
   HString GetPropertyEU(const HString &PropertyName, const HString &Default = "");

// 获得子结点数据，没有子结点则返回Default
   const HString GetValue(const char *Tag, const HString &Default = "");

// 获得子结点数据
   void GetValues(const char *Tag, vector<HString> &Result);

// 获得子结点数据并连接成一个字符串
   HString GetValues(const char *Tag);

// 获得子结点数据（转换环境变量），没有子结点则返回Default
   HString GetValueEnv(const char *Tag, const HString &Default = "");

// 获得子结点数据（转换环境变量）
   void GetValuesEnv(const char *Tag, vector<HString> &Result);

// 获得子结点数据（转大写），没有子结点则返回Default
   HString GetValueUpper(const char *Tag, const HString &Default = "");

// 获得子结点数据（转大写）
   void GetValuesUpper(const char *Tag, vector<HString> &Result);

// 获得子结点数据（转换环境变量、转大写），没有子结点则返回Default
   HString GetValueEU(const char *Tag, const HString &Default = "");

// 获得子结点数据（转换环境变量、转大写）
   void GetValuesEU(const char *Tag, vector<HString> &Result);

// 设置子结点数据，没有子结点则生成之
   void SetValue(const char *Tag, const HString &Data);
   void SetValue(const char *Tag, int Num);

// 设置一批子结点数据
   void SetValues(const char *Tag, const vector<HString> &Data,
      const char *SubItemTag = NULL);

// 设置一批子结点数据，数据源是一个字符串（用换行分隔的多行数据）
   void SetValues(const char *Tag, const HString &Data,
      const char *SubItemTag = NULL);

// 增加子结点并设置数据
   void AddValue(const char *Tag, const HString &Data);

// 获得指定名称的子结点指针
   HXmlTree *GetChild(const char *Tag);

// 获得指定名称的子结点指针，没有则创建之
   HXmlTree *ForceGetChild(const char *Tag);

// 获得指定名称的子结点指针数组，如果Tag为NULL，则获得所有子结点指针
   void GetChildren(const char *Tag, vector<HXmlTree*> &Children);

// 增加一个子结点
   void AddChild(HXmlTree *Child);

// 从文件读入XML树，成功返回true，失败返回false，可以用GetErrorString
// 得到错误信息
   bool LoadFromFile(const HString &FileName, bool UpperTag = true);

// 将XML树存储到文件，成功返回true，失败返回false，可以用GetErrorString
// 得到错误信息
   bool SaveToFile(const HString &FileName);

   bool LoadFromStream(h_base::HStream *Stream, bool UpperTag = true);
   void SaveToStream(h_base::HStream *Stream);
   
// 清空XML树的内容
   void Clear(void);

// 移动子树
   void MoveChildTo(HXmlTree *Child, HXmlTree *Des);

   void GetPropertyMap(map<HString, HString> &ResultMap) const ;

   static int AddXmlString(char *Buf, const char *s);

private :
   HXmlTree(const HXmlTree &rhs);
   HXmlTree& operator=(const HXmlTree &rhs);
   void SaveNodeToStream(h_base::HStream *Stream, int Level);
   bool IsValidTag(const char *Tag);
   void TranslateSpecialChar(char *w);
   const HString *FindStr(const char *Str);
   const HString *FindStr(const HString *Str);
   const HString *FindStr(const HString &Str);

   HString FErrorString;
   const HString *FTag;
   HString FData;
   bool FDeleteFlag;
   vector<HXmlTree*> *FChildren;
   HPropertyMap *FPropertyMap;
   set<HString> *FStrSet;
   bool FRootFlag;

   static HString NullStr;
};

}; // namespace h_base

#endif
